<template>
  <view class="mxp-swiper" :class="cusClass" :style="[cusStyle, { background, height, width, borderRadius: radius }]">
    <view v-if="loading" class="loading">
      <mxp-icon color="#999" size="24px" :spin="true" name="jiazai"></mxp-icon>
    </view>
    <swiper
      v-else
      class="wrapper"
      :style="{ height, flex: 1 }"
      :circular="circular"
      :vertical="vertical"
      :interval="interval"
      :duration="duration"
      :autoplay="newAutoplay"
      :current="currentIndex"
      :previousMargin="previousMargin"
      :nextMargin="nextMargin"
      :acceleration="acceleration"
      :displayMultipleItems="displayMultipleItems"
      :easingFunction="easingFunction"
      @change="change"
    >
      <swiper-item v-for="(item, index) in list" :key="index" class="mxp-swiper-item">
        <slot :item="item" :index="index" :currentIndex="currentIndex">
          <mxp-swiper-item
            :index="index"
            :item="item"
            :currentIndex="currentIndex"
            :urlKey="urlKey"
            :posterKey="posterKey"
            :titleKey="titleKey"
            :sourceTypeKey="sourceTypeKey"
            :previousMargin="previousMargin"
            :nextMargin="nextMargin"
            :videoAutoplay="videoAutoplay"
            :imgMode="imgMode"
            :height="height"
            :radius="radius"
            :showTitle="showTitle"
            :titleStyle="titleStyle"
            @click="clickHandler"
            @videoPlayChange="onVideoPlayChange"
          ></mxp-swiper-item>
        </slot>
      </swiper-item>
    </swiper>
    <view class="indicator" :style="[indicatorStyle]">
      <slot name="indicator">
        <mxp-swiper-indicator
          v-if="!loading && indicator && !showTitle"
          :indicatorActiveColor="indicatorActiveColor"
          :indicatorInactiveColor="indicatorInactiveColor"
          :length="list.length"
          :current="currentIndex"
          :indicatorMode="indicatorMode"
          @indicatorClick="onIndicatorClick"
        ></mxp-swiper-indicator>
      </slot>
    </view>
  </view>
</template>

<script lang="ts" setup>
  import { type CSSProperties, type PropType, ref, watch } from 'vue';
  import type { $AllColorStr, $SizeUnitStr } from '@/mxp-ui/mxp-tool/types/interface';
  import MxpIcon from '../mxp-icon/mxp-icon.vue';
  import MxpSwiperIndicator from './components/mxp-swiper-indicator.vue';
  import MxpSwiperItem from './components/mxp-swiper-item.vue';
  import { publicStyeProps } from '../mxp-tool/utils/public-props';
  import type { ImageMode, SwiperOnChangeEvent } from 'mxp-uni-types';
  defineOptions({
    name: 'mxp-swiper',
  });

  const props = defineProps({
    /** 列表数组，子元素可为字符串和对象，如为对象可通过 urlKey posterKey sourceTypeKey titleKey 指定目标属性名 */
    list: { type: Array as PropType<Record<string, unknown>[] | string[]>, default: () => [] },
    /** 当 list 为对象时，视频或图片链接的 key */
    urlKey: { type: String, default: 'url' },
    /** 当 list 为对象时，且为视频时，视频封面海报的 key */
    posterKey: { type: String, default: 'poster' },
    /** 当 list 为对象时，显示标题的 key */
    titleKey: { type: String, default: 'title' },
    /** 当 list 为对象时，资源类型的 key ，默认值为 undefined ，即：通过 url 去判断资源类型，注意：资源类型只能为 image 或 video， */
    sourceTypeKey: { type: String, default: undefined },
    /** 是否显示面板指示器 */
    indicator: { type: Boolean, default: true },
    /** 指示器非激活颜色 */
    indicatorActiveColor: { type: String as PropType<$AllColorStr>, default: '#fff' },
    /** 指示器的激活颜色 */
    indicatorInactiveColor: { type: String as PropType<$AllColorStr>, default: 'rgba(255, 255, 255, 0.35)' },
    /** 指示器样式，可通过bottom，left，right进行定位 */
    indicatorStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
    /** 指示器模式，line-线型，dot-点型 */
    indicatorMode: { type: String as PropType<'dot' | 'line'>, default: 'line' },
    /** 是否自动切换 */
    autoplay: { type: Boolean, default: true },
    /** 当滚动到视频页时是否自动播放 */
    videoAutoplay: { type: Boolean, default: false },
    /** 当前所在滑块的 index */
    current: { type: Number, default: 0 },
    /** 滑块自动切换时间间隔 */
    interval: { type: Number, default: 3000 },
    /** 滑块切换过程所需时间 */
    duration: { type: Number, default: 300 },
    /** 播放到末尾后是否重新回到开头 */
    circular: { type: Boolean, default: false },
    /** 滑动方向是否为纵向 */
    vertical: { type: Boolean, default: false },
    /** 前边距，可用于露出前一项的一小部分，nvue和支付宝不支持 */
    previousMargin: { type: String as PropType<$SizeUnitStr>, default: '0px' },
    /** 后边距，可用于露出后一项的一小部分，nvue和支付宝不支持 */
    nextMargin: { type: String as PropType<$SizeUnitStr>, default: '0px' },
    /** 当开启时，会根据滑动速度，连续滑动多屏，支付宝不支持 */
    acceleration: { type: Boolean, default: false },
    /** 同时显示的滑块数量，nvue、支付宝小程序不支持 */
    displayMultipleItems: { type: Number, default: 1 },
    /** 指定swiper切换缓动动画类型，有效值：default、linear、easeInCubic、easeOutCubic、easeInOutCubic 只对微信小程序有效  */
    easingFunction: { type: String as PropType<'default' | 'easeInCubic' | 'easeInOutCubic' | 'easeOutCubic' | 'linear'>, default: 'default' },
    /** 图片的裁剪模式 */
    imgMode: { type: String as PropType<ImageMode>, default: 'aspectFill' },
    /** 组件高度 (单张图片或视频的高度与组件高度相同) */
    height: { type: String as PropType<$SizeUnitStr>, default: '360rpx' },
    /** 组件宽度 (单张图片或视频的宽度位组件宽度减去previousMargin和nextMargin后的宽度) */
    width: { type: String as PropType<$SizeUnitStr>, default: '100%' },
    /** 背景颜色 */
    background: { type: String as PropType<$AllColorStr>, default: 'transparent' },
    /** 组件圆角，数值或带单位的字符串 */
    radius: { type: String as PropType<$SizeUnitStr>, default: '4px' },
    /** 是否加载中 */
    loading: { type: Boolean, default: false },
    /** 是否显示标题，要求数组对象中有title属性 */
    showTitle: { type: Boolean, default: false },
    /** 显示的标题样式 */
    titleStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
    ...publicStyeProps,
  });
  defineSlots<{
    /** 自定义 主体内容 */
    default: (data: { item: any; index: number; currentIndex: number }) => void;
    /** 自定义 指示器 */
    indicator: () => void;
  }>();
  const emits = defineEmits<{
    (e: 'click', val: number): void;
    (e: 'change', val: SwiperOnChangeEvent): void;
  }>();
  const currentIndex = ref(0);
  const newAutoplay = ref(props.autoplay);

  watch(
    () => props.current,
    (val) => {
      currentIndex.value = val; // 和上游数据关联上
    }
  );

  /**
   * 轮播切换事件
   */
  function change(e: SwiperOnChangeEvent) {
    // 当前的激活索引
    const { current } = e.detail;
    currentIndex.value = current;
    emits('change', e);
  }

  /**
   * 点击某个item
   */
  function clickHandler(index: number) {
    emits('click', index);
  }

  /** 监听视频是否正在播放 */
  function onVideoPlayChange(state: boolean) {
    newAutoplay.value = !state;
  }

  /** 点击指示器 */
  function onIndicatorClick(index: number) {
    currentIndex.value = index;
  }
</script>

<style lang="scss" scoped>
  .mxp-swiper {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    overflow: hidden;

    .indicator {
      position: absolute;
      bottom: 10px;
    }
  }
</style>
